package org.apache.james.mime4j.parser;

import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.logging.Log;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.decoder.Base64InputStream;
import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
import org.apache.james.mime4j.descriptor.BodyDescriptor;
import org.apache.james.mime4j.descriptor.MutableBodyDescriptor;
import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
import org.apache.james.mime4j.io.LimitedInputStream;
import org.apache.james.mime4j.io.LineReaderInputStream;
import org.apache.james.mime4j.io.LineReaderInputStreamAdaptor;
import org.apache.james.mime4j.io.MimeBoundaryInputStream;
import org.apache.james.mime4j.io.RootInputStream;
import org.apache.james.mime4j.util.MimeUtil;

public class MimeEntity extends AbstractEntity
{
  private static final int T_IN_BODYPART = -2;
  private static final int T_IN_MESSAGE = -3;
  private LineReaderInputStreamAdaptor dataStream;
  private final BufferedLineReaderInputStream inbuffer;
  private MimeBoundaryInputStream mimeStream;
  private int recursionMode;
  private final RootInputStream rootStream;
  private boolean skipHeader;
  private byte[] tmpbuf;

  public MimeEntity(RootInputStream paramRootInputStream, BufferedLineReaderInputStream paramBufferedLineReaderInputStream, BodyDescriptor paramBodyDescriptor, int paramInt1, int paramInt2)
  {
    this(paramRootInputStream, paramBufferedLineReaderInputStream, paramBodyDescriptor, paramInt1, paramInt2, new MimeEntityConfig());
  }

  public MimeEntity(RootInputStream paramRootInputStream, BufferedLineReaderInputStream paramBufferedLineReaderInputStream, BodyDescriptor paramBodyDescriptor, int paramInt1, int paramInt2, MimeEntityConfig paramMimeEntityConfig)
  {
    super(paramBodyDescriptor, paramInt1, paramInt2, paramMimeEntityConfig);
    this.rootStream = paramRootInputStream;
    this.inbuffer = paramBufferedLineReaderInputStream;
    this.dataStream = new LineReaderInputStreamAdaptor(paramBufferedLineReaderInputStream, paramMimeEntityConfig.getMaxLineLen());
    this.skipHeader = false;
  }

  private void advanceToBoundary()
    throws IOException
  {
    if (!(this.dataStream.eof()))
    {
      if (this.tmpbuf == null)
        this.tmpbuf = new byte[2048];
      InputStream localInputStream = getLimitedContentStream();
      do;
      while (localInputStream.read(this.tmpbuf) != -1);
    }
  }

  private void clearMimeStream()
  {
    this.mimeStream = null;
    this.dataStream = new LineReaderInputStreamAdaptor(this.inbuffer, this.config.getMaxLineLen());
  }

  private void createMimeStream()
    throws IOException
  {
    String str = this.body.getBoundary();
    int i = 2 * str.length();
    if (i < 4096)
      i = 4096;
    try
    {
      if (this.mimeStream != null)
      {
        this.mimeStream = new MimeBoundaryInputStream(new BufferedLineReaderInputStream(this.mimeStream, i, this.config.getMaxLineLen()), str);
        this.dataStream = new LineReaderInputStreamAdaptor(this.mimeStream, this.config.getMaxLineLen());
        return;
      }
      this.inbuffer.ensureCapacity(i);
      this.mimeStream = new MimeBoundaryInputStream(this.inbuffer, str);
    }
    catch (IllegalArgumentException localIllegalArgumentException)
    {
      throw new MimeException(localIllegalArgumentException.getMessage(), localIllegalArgumentException);
    }
  }

  private InputStream getLimitedContentStream()
  {
    Object localObject;
    long l = this.config.getMaxContentLen();
    if (l >= 0L)
      localObject = new LimitedInputStream(this.dataStream, l);
    while (true)
    {
      return localObject;
      localObject = this.dataStream;
    }
  }

  private EntityStateMachine nextMessage()
  {
    Object localObject1;
    Object localObject2;
    String str = this.body.getTransferEncoding();
    if (MimeUtil.isBase64Encoding(str))
    {
      this.log.debug("base64 encoded message/rfc822 detected");
      localObject1 = new Base64InputStream(this.dataStream);
      if (this.recursionMode != 2)
        break label100;
      localObject2 = new RawEntity((InputStream)localObject1);
    }
    while (true)
    {
      while (true)
      {
        while (true)
        {
          return localObject2;
          if (!(MimeUtil.isQuotedPrintableEncoded(str)))
            break;
          this.log.debug("quoted-printable encoded message/rfc822 detected");
          localObject1 = new QuotedPrintableInputStream(this.dataStream);
        }
        localObject1 = this.dataStream;
      }
      label100: localObject2 = new MimeEntity(this.rootStream, new BufferedLineReaderInputStream((InputStream)localObject1, 4096, this.config.getMaxLineLen()), this.body, 0, 1, this.config);
      ((MimeEntity)localObject2).setRecursionMode(this.recursionMode);
    }
  }

  private EntityStateMachine nextMimeEntity()
  {
    Object localObject;
    if (this.recursionMode == 2)
      localObject = new RawEntity(this.mimeStream);
    while (true)
    {
      return localObject;
      BufferedLineReaderInputStream localBufferedLineReaderInputStream = new BufferedLineReaderInputStream(this.mimeStream, 4096, this.config.getMaxLineLen());
      MimeEntity localMimeEntity = new MimeEntity(this.rootStream, localBufferedLineReaderInputStream, this.body, 10, 11, this.config);
      localMimeEntity.setRecursionMode(this.recursionMode);
      localObject = localMimeEntity;
    }
  }

  public EntityStateMachine advance()
    throws IOException, MimeException
  {
    switch (this.state)
    {
    case -1:
    case 1:
    case 2:
    case 11:
    default:
      if (this.state == this.endState)
        this.state = -1;
    case 0:
    case 10:
    case 3:
    case 4:
    case 5:
    case 6:
    case 8:
    case -2:
    case 9:
    case -3:
    case 7:
    case 12:
    }
    while (true)
    {
      while (true)
      {
        EntityStateMachine localEntityStateMachine = null;
        while (true)
        {
          while (true)
          {
            while (true)
            {
              while (true)
              {
                while (true)
                {
                  while (true)
                  {
                    while (true)
                    {
                      String str;
                      while (true)
                      {
                        while (true)
                        {
                          int i;
                          while (true)
                          {
                            while (true)
                            {
                              while (true)
                              {
                                return localEntityStateMachine;
                                if (!(this.skipHeader))
                                  break;
                                this.state = 5;
                              }
                              this.state = 3;
                            }
                            this.state = 3;
                          }
                          if (parseField())
                            i = 4;
                          while (true)
                          {
                            while (true)
                              this.state = i;
                            i = 5;
                          }
                          str = this.body.getMimeType();
                          if (this.recursionMode != 3)
                            break;
                          this.state = 12;
                        }
                        if (!(MimeUtil.isMultipart(str)))
                          break;
                        this.state = 6;
                        clearMimeStream();
                      }
                      if ((this.recursionMode == 1) || (!(MimeUtil.isMessage(str))))
                        break;
                      this.state = -3;
                      localEntityStateMachine = nextMessage();
                    }
                    this.state = 12;
                  }
                  if (!(this.dataStream.isUsed()))
                    break;
                  advanceToBoundary();
                  this.state = 7;
                }
                createMimeStream();
                this.state = 8;
              }
              advanceToBoundary();
              if (!(this.mimeStream.isLastPart()))
                break;
              clearMimeStream();
              this.state = 7;
            }
            clearMimeStream();
            createMimeStream();
            this.state = -2;
            localEntityStateMachine = nextMimeEntity();
          }
          advanceToBoundary();
          if ((this.mimeStream.eof()) && (!(this.mimeStream.isLastPart())))
            monitor(Event.MIME_BODY_PREMATURE_END);
          do
            while (true)
            {
              clearMimeStream();
              this.state = 9;
            }
          while (this.mimeStream.isLastPart());
          clearMimeStream();
          createMimeStream();
          this.state = -2;
          localEntityStateMachine = nextMimeEntity();
        }
        this.state = 7;
      }
      this.state = this.endState;
    }
    throw new IllegalStateException("Invalid state: " + stateToString(this.state));
  }

  public InputStream getContentStream()
  {
    switch (this.state)
    {
    case 7:
    case 10:
    case 11:
    default:
      throw new IllegalStateException("Invalid state: " + stateToString(this.state));
    case 6:
    case 8:
    case 9:
    case 12:
    }
    return getLimitedContentStream();
  }

  protected LineReaderInputStream getDataStream()
  {
    return this.dataStream;
  }

  protected int getLineNumber()
  {
    return this.rootStream.getLineNumber();
  }

  public int getRecursionMode()
  {
    return this.recursionMode;
  }

  public void setRecursionMode(int paramInt)
  {
    this.recursionMode = paramInt;
  }

  public void skipHeader(String paramString)
  {
    if (this.state != 0)
      throw new IllegalStateException("Invalid state: " + stateToString(this.state));
    this.skipHeader = true;
    this.body.addField("Content-Type", paramString);
  }
}